Day 1 只跑通了環境,今天要碰真正的 JavaScript 語法——變數(variable)與資料型別(data type)。
JavaScript 宣告變數常用兩個關鍵字:
let hp = 100; // 之後可以改
const heroName = "勇者"; // 宣告後不能再改
想了一下要怎麼記住這兩個的差別,我覺得:let 像一塊蛋糕胚,之後想怎麼塗改、拆解都可以;const 像一塊岩石,一旦放定了就不能被撼動。
hp(血量)這種之後會一直變動的資料,適合用 let;heroName(角色名字)這種通常不會再變的資料,適合用 const。

這裡我特地測試了兩種情況,因為我發現它們的行為完全不同。
const heroName = "勇者";
const heroName = "新生兒";
這會產生 SyntaxError(語法錯誤):Identifier 'heroName' has already been declared。
關鍵是:JavaScript 會先把整份程式碼「讀一遍」確認語法都合法,才開始真正執行。所以這個錯誤不是「跑到那行才失敗」,而是整支程式從頭到尾都不會執行,連前面沒問題的程式碼也一起被拖累。
我把重新賦值(下面會講的情況二)跟重複宣告寫在同一支檔案裡測試,VS Code 對這兩種寫法的反應完全不同:重新賦值那行,編輯器沒有跳出任何警告;重複宣告那行,打字的當下就直接被畫上紅色波浪線,根本不用等執行。

const heroName = "勇者";
heroName = "初心者";
理論上這會產生 TypeError(型別錯誤):Assignment to constant variable.,而且是執行到那一行的當下才會發生,跟情況一「還沒開始跑就整個失敗」不一樣。
但實際測試時,我發現一件更有意思的事:我根本沒看到這個 TypeError 出現過。

因為我的測試檔案裡,重新賦值(情況二)跟重複宣告(情況一)同時存在,而重複宣告是語法錯誤,在「讀一遍」的階段就被抓到——這代表整支程式根本沒有進入「執行」階段,連帶讓原本應該在執行到那一行才會噴出的 TypeError,根本沒有機會發生。我只看得到 SyntaxError,TypeError 被擋在前面,沒機會現身。這反而是「JavaScript 會先讀一遍全部程式碼才開始執行」這件事最直接的證明。
不會,而且我覺得這個問題本身很有意思。404 是瀏覽器層級的錯誤,代表「檔案根本找不到」,瀏覽器會整頁換成一個錯誤畫面。但 const 出錯是網頁已經載入成功之後,程式邏輯內部的問題——網頁畫面照樣顯示正常,只有打開 Console 才看得到這兩個錯誤訊息。這算是我今天釐清的一個誤會:網頁「打不開」和網頁「打開了但邏輯壞掉」,是完全不同層次的問題。
JavaScript 最常見的三種型別:
let hp = 100; // number(數字)
let heroName = "勇者"; // string(字串)
let isAlive = true; // boolean(布林,只有 true/false)
用 typeof 可以問 JavaScript「這是什麼型別」:
console.log(typeof hp); // "number"
console.log(typeof heroName); // "string"
console.log(typeof isAlive); // "boolean"
我自己也跑了一個很多人會踩到的例外:
console.log(typeof null);

答案是 "object"——null 明明代表「空值」,卻被判定成物件型別,一開始看到我也愣了一下。查了才知道,這其實是 JavaScript 一個很有名的歷史包袱:1995 年 JS 剛誕生時的內部設計就把 null 判定成 object,官方後來也承認這是個失誤,但因為全世界已經有太多網站的程式碼依賴這個行為,修正它反而會讓大量既有網站壞掉,所以這個 bug 就這樣被永遠留著。這讓我想到 QA 工作裡常遇到的情況:有時候修一個已知的小 bug,風險比留著它不動還大。
寫這篇之前,我特地查證了一下「JS 不用像其他語言一樣先說明是整數/字串/布林」這個特性,實際上該拿誰來當對照組。查完發現:Python 同樣不用事先宣告型別,兩者都是「動態型別」語言,變數的型別是看塞了什麼值進去自動決定的。
真正需要「先宣告型別」的,是像 Java 這種「靜態型別」語言:
int hp = 100; // 要先寫 int
String name = "勇者"; // 要先寫 String
所以正確的對照應該是「JS 和 Python 同一陣營(動態型別),Java 才是真正的對照組(靜態型別)」——這個對照組抓對了,之後理解為什麼有些語言要寫這麼多型別宣告,會更清楚。
今天搞懂的事:
let 能改、const 不能改,但要記得「不能改」指的是不能重新賦值,之後學到物件時會有例外(先劇透一下)明天繼續學字串與模板字串。